Skip to content

Fix for stale data when hovering#3084

Draft
matt-aitken wants to merge 1 commit intomainfrom
chart-highlight-fix
Draft

Fix for stale data when hovering#3084
matt-aitken wants to merge 1 commit intomainfrom
chart-highlight-fix

Conversation

@matt-aitken
Copy link
Member

  • Ensure hover displays up-to-date information rather than cached/stale values

@changeset-bot
Copy link

changeset-bot bot commented Feb 18, 2026

⚠️ No Changeset found

Latest commit: bb92113

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 18, 2026

Walkthrough

This change modifies the data aggregation logic in the ChartLegendCompound component. The currentTotal calculation now derives data from the complete data row (activePayload[0]?.payload) and maps all dataKeys to build rawValues, ensuring comprehensive coverage of all data keys rather than only visible series. Similarly, the currentData calculation constructs hover data by reading from the full data row for every key in dataKeys. Dependency arrays in useMemo are updated to include dataKeys, and supporting comments are adjusted to reflect these implementation changes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete and lacks required sections from the template including issue reference, checklist, testing details, and changelog. Complete the description with issue number, test methodology, detailed changelog, and verify all template checklist items are addressed.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix for stale data when hovering' directly and clearly describes the main change: fixing stale data issues in hover interactions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chart-highlight-fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (1)

74-94: Optional: extract activePayload[0]?.payload into a shared useMemo.

dataRow is derived identically in both currentTotal and currentData. Extracting it reduces duplication and makes the relationship between the two memos explicit.

♻️ Suggested refactor
+  // Resolve the full data row for the hovered point once, shared by both total and per-series calculations
+  const hoveredDataRow = useMemo(() => {
+    if (!activePayload?.length) return null;
+    return activePayload[0]?.payload ?? null;
+  }, [activePayload]);

   const currentTotal = useMemo((): number | null => {
     if (!activePayload?.length) return grandTotal;
-    const dataRow = activePayload[0]?.payload;
-    if (!dataRow) return grandTotal;
+    if (!hoveredDataRow) return grandTotal;
-    const rawValues = dataKeys.map((key) => dataRow[key]);
+    const rawValues = dataKeys.map((key) => hoveredDataRow[key]);
     ...
-  }, [activePayload, grandTotal, dataKeys, aggregation]);
+  }, [hoveredDataRow, grandTotal, dataKeys, aggregation]);

   const currentData = useMemo((): Record<string, number | null> => {
     if (!activePayload?.length) return totals;
-    const dataRow = activePayload[0]?.payload;
-    if (!dataRow) return totals;
+    if (!hoveredDataRow) return totals;
     const hoverData: Record<string, number | null> = {};
     for (const key of dataKeys) {
-      const value = dataRow[key];
+      const value = hoveredDataRow[key];
       ...
     }
     ...
-  }, [activePayload, totals, dataKeys]);
+  }, [hoveredDataRow, totals, dataKeys]);

Also applies to: 112-132

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx` around
lines 74 - 94, Extract the repeated expression activePayload[0]?.payload into a
shared useMemo (e.g., activeDataRow or currentRow) and use that memo in both
currentTotal and currentData; create the memo like const activeDataRow =
useMemo(() => activePayload?.[0]?.payload, [activePayload]) then replace local
dataRow usages in the currentTotal and currentData useMemo blocks with
activeDataRow and update their dependency arrays to depend on activeDataRow
instead of activePayload to remove duplication and make the relationship
explicit.
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb0f963 and bb92113.

📒 Files selected for processing (1)
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
🧠 Learnings (1)
📚 Learning: 2026-02-11T16:37:32.429Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/components/primitives/charts/Card.tsx:26-30
Timestamp: 2026-02-11T16:37:32.429Z
Learning: In projects using react-grid-layout, avoid relying on drag-handle class to imply draggability. Ensure drag-handle elements only affect dragging when the parent grid item is configured draggable in the layout; conditionally apply cursor styles based on the draggable prop. This improves correctness and accessibility.

Applied to files:

  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
🔇 Additional comments (1)
apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (1)

77-81: LGTM — deriving from activePayload[0]?.payload is the right fix.

Reading the raw data row directly ensures the total covers all dataKeys, not just the visible series present in activePayload. The null-guard on line 79 and the unchanged filtering/aggregation logic below preserve the existing gap-fill semantics correctly.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx`:
- Around line 115-132: The current logic in ChartLegendCompound (inside the
useMemo that reads activePayload -> dataRow) skips keys when dataRow[key] ===
undefined, causing a fallback to totals; to make absent keys render as a dash
instead, change the loop that builds hoverData (iterating dataKeys) so that
instead of skipping undefined you explicitly set hoverData[key] = null when
value === undefined, while preserving the existing Number(value) conversion for
non-null values; update the logic around hoverData/dataRow/dataKeys to ensure
absent keys are treated the same as explicit nulls (so spread {...totals,
...hoverData} yields null for absent keys) and adjust any downstream rendering
that expects null to display the dash.

---

Nitpick comments:
In `@apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx`:
- Around line 74-94: Extract the repeated expression activePayload[0]?.payload
into a shared useMemo (e.g., activeDataRow or currentRow) and use that memo in
both currentTotal and currentData; create the memo like const activeDataRow =
useMemo(() => activePayload?.[0]?.payload, [activePayload]) then replace local
dataRow usages in the currentTotal and currentData useMemo blocks with
activeDataRow and update their dependency arrays to depend on activeDataRow
instead of activePayload to remove duplication and make the relationship
explicit.

Comment on lines +115 to +132
// Use the full data row so ALL dataKeys are resolved from the hovered point,
// not just the visibleSeries present in activePayload.
const dataRow = activePayload[0]?.payload;
if (!dataRow) return totals;

const hoverData: Record<string, number | null> = {};
for (const key of dataKeys) {
const value = dataRow[key];
if (value !== undefined) {
hoverData[key] = value != null ? Number(value) || 0 : null;
}
}

// Return a merged object - totals for keys not in the hover data
return {
...totals,
...hoverData,
};
}, [activePayload, totals]);
}, [activePayload, totals, dataKeys]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

One subtle behaviour worth confirming: undefined keys fall back to totals.

Keys absent from dataRow (i.e. dataRow[key] === undefined) are intentionally excluded from hoverData, so the spread on line 129 (...totals, ...hoverData) falls back to the series total for those keys rather than showing a dash. This is distinct from keys that are explicitly null (gap-fill → shown as ).

If a dataKey could be legitimately absent from a data row in a non-gap scenario (e.g., sparse datasets), hovering would silently show the aggregate total for that series instead of , which might mislead users. Please confirm this edge-case is handled as intended or add an explicit mapping to null for absent keys if the dash behaviour is preferred.

💡 Alternative: treat absent keys as null (show dash on hover)
     for (const key of dataKeys) {
       const value = dataRow[key];
-      if (value !== undefined) {
-        hoverData[key] = value != null ? Number(value) || 0 : null;
-      }
+      hoverData[key] = value != null ? Number(value) || 0 : null;
     }

This would make absent and explicit-null keys both render as when hovering, which may be the safer default for sparse data.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx` around
lines 115 - 132, The current logic in ChartLegendCompound (inside the useMemo
that reads activePayload -> dataRow) skips keys when dataRow[key] === undefined,
causing a fallback to totals; to make absent keys render as a dash instead,
change the loop that builds hoverData (iterating dataKeys) so that instead of
skipping undefined you explicitly set hoverData[key] = null when value ===
undefined, while preserving the existing Number(value) conversion for non-null
values; update the logic around hoverData/dataRow/dataKeys to ensure absent keys
are treated the same as explicit nulls (so spread {...totals, ...hoverData}
yields null for absent keys) and adjust any downstream rendering that expects
null to display the dash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments